package cn.acheng1314.im.socket.server;

import cn.acheng1314.im.common.server.AbstractServer;
import cn.acheng1314.im.socket.coder.SocketMessageDecoder;
import cn.acheng1314.im.socket.coder.SocketMessageEncoder;
import cn.acheng1314.im.socket.handler.SocketHeartbeatHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

/**
 * 服务器的实现
 */
public class SocketServerImpl extends AbstractServer {

    private static final Logger logger = LoggerFactory.getLogger(SocketServerImpl.class);

    @Override
    public void bind() {
        super.init();
//        handlers.put(ImConstant.CLIENT_HEARTBEAT, new ServerHeartbeatHandler());
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);
        bootstrap.childOption(ChannelOption.TCP_NODELAY, tcpNoDelay);
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, keepAlive);
        bootstrap.channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                //添加定制化处理器
                handlers.forEach(pipeline::addLast);

                //消息处理器
                ch.pipeline().addLast(new SocketMessageDecoder());
                ch.pipeline().addLast(new SocketMessageEncoder());
                ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));

                //开启心跳检查，添加心跳处理器
                if (checkHeartbeat) {
                    timeoutHandler = new IdleStateHandler(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds);
                    pipeline.addLast("timeoutHandler", timeoutHandler);
                    pipeline.addLast("heartbeatHandler", new SocketHeartbeatHandler());
                }

                /*
                 * todo 这里可以考虑引入线程池进行消息的分发，以便于程序解耦提高效率
                 */

            }
        });

        final InetSocketAddress socketAddress = new InetSocketAddress(port);
        ChannelFuture bind = bootstrap.bind(socketAddress);
        bind.addListener((ChannelFutureListener) ch -> {
            ch.await();
            if (ch.isSuccess()) {
                logger.info("Server started, listening on '{}.", socketAddress);
            } else {
                logger.error("Failed to start Server '{}', caused by: '{}'.", socketAddress, ch.cause());
            }
        });
        bind.channel().closeFuture().addListener(future -> this.shutdown());
    }

    @Override
    public void shutdown() {
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
    }
}
